#include "postgres.h"

#include "port/fdb_crypt.h"
#include <string.h>
#ifdef FDDGM
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#endif


static void fc_fdb_rc4_crypt(struct fdb_cipher_state *const fc_state, const unsigned char *fc_inbuf, 
                   unsigned char *fc_outbuf, int fc_buflen);

static void fc_fdb_xor_crypt(struct fdb_cipher_state *const fc_state,  const unsigned char *fc_inbuf, 
					unsigned char *fc_outbuf, int fc_buflen);

#ifdef FDDGM
static void fc_fdb_sm4_xts_init(struct fdb_cipher_state *const fc_state, FDB_ENCRYPT_TYPE fc_type, const unsigned char *fc_key, int fc_keylen, const unsigned char *fc_iv);
static void fc_fdb_sm4_xts_encrypt(struct fdb_cipher_state *const fc_state, const unsigned char *fc_inbuf, unsigned char *fc_outbuf, int fc_buflen);
static void fc_fdb_sm4_xts_decrypt(struct fdb_cipher_state *const fc_state,  const unsigned char *fc_inbuf, unsigned char *fc_outbuf, int fc_buflen);

/*
 * 获取传入的SSL错误码的原因字符串
 *
 * ERR_get_error()由调用者使用，以获取错误码以传递到此处。
 *
 * 在这里需要一些谨慎，因为如果不识别错误代码，ERR_reason_error_string将
 * 返回NULL。我们不想返回NULL。
 */
static const char * fc_SSLerrmessage(unsigned long fc_ecode)
{
	const char *fc_errreason;
	static char fc_errbuf[36];

	if (fc_ecode == 0)
		return _("no SSL error reported");
	fc_errreason = ERR_reason_error_string(fc_ecode);
	if (fc_errreason != NULL)
		return fc_errreason;
	snprintf(fc_errbuf, sizeof(fc_errbuf), _("SSL error code %lu"), fc_ecode);
	return fc_errbuf;
}
#endif


static void fc_swap_bytes(unsigned char *fc_a, unsigned char *fc_b)
{
    unsigned char fc_temp = *fc_a;
    *fc_a = *fc_b;
    *fc_b = fc_temp;
}

const char* fdb_encrypttype_tochar(FDB_ENCRYPT_TYPE fc_type)
{
	switch(fc_type)
	{
		case FDB_ENCRYPT_TYPE_NONE:
		{
			return "plain";
		}
		case FDB_ENCRYPT_TYPE_XOR:
		{
			return "xor";
		}
		case FDB_ENCRYPT_TYPE_RC4:
		{
			return "rc4"; 		
		}
#ifdef FDDGM
		case FDB_ENCRYPT_TYPE_SM4:
		{
			return "sm4";
		}
#endif
		default:
		{
			ereport(ERROR,	(errmsg("Unsupport encrpty type: %d",fc_type)));	
		}
	}

}


/*
* 初始化加密结构
*/
void fdb_cipher_init(struct fdb_cipher_state *const fc_state, FDB_ENCRYPT_TYPE fc_type, const unsigned char *fc_key, int fc_keylen, const unsigned char *fc_iv)
{    
    int fc_i = 0;
	unsigned char fc_j = 0;

	if(FDB_ENCRYPT_TYPE_SM4 == fc_type)
	{
#ifdef FDDGM
		return fc_fdb_sm4_xts_init(fc_state, fc_type, fc_key, fc_keylen, fc_iv);
#else
		ereport(ERROR,	(errmsg("Unsupport encrpty type: %d",fc_type)));
#endif
	}

	fc_state->type = fc_type;
    
    for (fc_i = 0; fc_i < FDB_CRYPT_PER_LEN; fc_i++)
	{
        fc_state->perm[fc_i] = (unsigned char)fc_i;
	}
	
    fc_state->index1 = 0;
    fc_state->index2 = 0;
   
    for (fc_j = fc_i = 0; fc_i < FDB_CRYPT_PER_LEN; fc_i++) 
	{
        fc_j = (fc_j + fc_state->perm[fc_i] + fc_key[fc_i % fc_keylen]) % FDB_CRYPT_PER_LEN;
        fc_swap_bytes(&fc_state->perm[fc_i], &fc_state->perm[fc_j]);
    }
    memcpy(fc_state->pkey, fc_state->perm, FDB_CRYPT_PER_LEN);
}

/*
 *复位秘钥
 */
void fdb_cipher_reset(struct fdb_cipher_state *const fc_state)
{
    memcpy(fc_state->perm, fc_state->pkey, FDB_CRYPT_PER_LEN);
    fc_state->index1 = 0;
    fc_state->index2 = 0;
}

void fdb_encrypt(struct fdb_cipher_state *const fc_state, const unsigned char *fc_inbuf, unsigned char *fc_outbuf, int fc_buflen)
{
	switch(fc_state->type)
	{
		case FDB_ENCRYPT_TYPE_NONE:
		{
			break;//不需要加解密
		}
		case FDB_ENCRYPT_TYPE_XOR:
		{
			return fc_fdb_xor_crypt(fc_state, fc_inbuf, fc_outbuf, fc_buflen);
		}
		case FDB_ENCRYPT_TYPE_RC4:
		{
			return fc_fdb_rc4_crypt(fc_state, fc_inbuf, fc_outbuf, fc_buflen);			
		}
#ifdef FDDGM
		case FDB_ENCRYPT_TYPE_SM4:
		{
			return fc_fdb_sm4_xts_encrypt(fc_state, fc_inbuf, fc_outbuf, fc_buflen);
		}
#endif
		default:
		{
			ereport(ERROR,	(errmsg("Unsupport encrpty type: %d",fc_state->type)));	
		}
	}
}


void fdb_decrypt(struct fdb_cipher_state *const fc_state,  const unsigned char *fc_inbuf, unsigned char *fc_outbuf, int fc_buflen)
{
	switch(fc_state->type)
	{
		case FDB_ENCRYPT_TYPE_NONE:
		{
			break;//不需要加解密
		}
		case FDB_ENCRYPT_TYPE_XOR:
		{
			return fc_fdb_xor_crypt(fc_state, fc_inbuf, fc_outbuf, fc_buflen);
			break;
		}
		case FDB_ENCRYPT_TYPE_RC4:
		{
			return fc_fdb_rc4_crypt(fc_state, fc_inbuf, fc_outbuf, fc_buflen);
			break;
		}
#ifdef FDDGM
		case FDB_ENCRYPT_TYPE_SM4:
		{
			return fc_fdb_sm4_xts_decrypt(fc_state, fc_inbuf, fc_outbuf, fc_buflen);
			break;
		}
#endif
		default:
		{
			ereport(ERROR,	(errmsg("Unsupport decrypt type: %d",fc_state->type)));	
		}
	}
}


/*
* RC4 encryption and decryption function
* Encryption and decryption are the same function
*/
static void fc_fdb_rc4_crypt(struct fdb_cipher_state *const fc_state, const unsigned char *fc_inbuf, 
                   unsigned char *fc_outbuf, int fc_buflen)
{
    int fc_i = 0;
    unsigned char fc_j = 0;
    for (fc_i = 0; fc_i < fc_buflen; fc_i++)
	{
        /* 更新修改索引 */
        fc_state->index1 = (fc_state->index1 + 1) % FDB_CRYPT_PER_LEN;
        fc_state->index2 = (fc_state->index2 + fc_state->perm[fc_state->index1]) % FDB_CRYPT_PER_LEN;
        /* 修改排列 */
        fc_swap_bytes(&fc_state->perm[fc_state->index1], &fc_state->perm[fc_state->index2]);
        /* 加解密下一个字节 */
        fc_j = (fc_state->perm[fc_state->index1] + fc_state->perm[fc_state->index2]) % FDB_CRYPT_PER_LEN;
        fc_outbuf[fc_i] = fc_inbuf[fc_i] ^ fc_state->perm[fc_j];
    }
}


/*
* XOR encryption and decryption function 
* Encryption and decryption are the same function
*/
static void fc_fdb_xor_crypt(struct fdb_cipher_state *const fc_state, const  unsigned char *fc_inbuf, 
                   unsigned char *fc_outbuf, int fc_buflen)
{
	int fc_i = 0;
	unsigned char fc_j = fc_state->index1;
	for (fc_i = 0; fc_i < fc_buflen; fc_i++) 
	{			
		/* 加解密下一个字节 */			
		fc_outbuf[fc_i] = fc_inbuf[fc_i] ^ fc_state->perm[(fc_j++)%FDB_CRYPT_PER_LEN];
	}
    fc_state->index1 = fc_j;
}

#ifdef FDDGM

/*
* Initialize sm4_xts
*/
static void fc_fdb_sm4_xts_init(struct fdb_cipher_state *const fc_state, FDB_ENCRYPT_TYPE fc_type, const unsigned char *fc_key, int fc_keylen, const unsigned char *fc_iv)
{
	int fc_i = 0;
	unsigned char fc_j = 0;

	if(NULL == fc_key)
	{
		ereport(ERROR,	(errmsg("sm4_xts init: key is null! ")));	
	}

	if(fc_keylen > FDB_SM4_XTS_KEY_LEN)
	{
		ereport(ERROR,	(errmsg("sm4_xts init: keylen(%d) is too long,is over 32! ",fc_keylen)));	
	}

	fc_state->type = fc_type;

	for (fc_i = 0; fc_i < FDB_CRYPT_PER_LEN; fc_i++)
	{
        fc_state->perm[fc_i] = (unsigned char)fc_i;
	} 
   
    for (fc_j = fc_i = 0; fc_i < FDB_SM4_XTS_KEY_LEN; fc_i++) 
	{
        fc_j = (fc_j + fc_state->perm[fc_i] + fc_key[fc_i % fc_keylen]) % FDB_CRYPT_PER_LEN;//保证其结果不会超过256
        fc_swap_bytes(&fc_state->perm[fc_i], &fc_state->perm[fc_j]);
    }  
	
	memset(fc_state->pkey, 0, FDB_SM4_XTS_KEY_LEN);	
	memcpy(fc_state->pkey, fc_state->perm, FDB_SM4_XTS_KEY_LEN);

	memset(fc_state->iv, 0, FDB_SM4_XTS_IV_LEN);
	if(NULL != fc_iv)
	{		
		memcpy(fc_state->iv, fc_iv, FDB_SM4_XTS_IV_LEN);
	}
}

/*
* sm4_xts encryption function
*/
static void fc_fdb_sm4_xts_encrypt(struct fdb_cipher_state *const fc_state, const unsigned char *fc_inbuf, unsigned char *fc_outbuf, int fc_buflen)
{
	EVP_CIPHER_CTX *fc_ctx = NULL;
	int fc_len = 0;
	int fc_ciphertext_len = 0;

	/* 创建并初始化sm4 xts上下文 */
	if(!(fc_ctx = EVP_CIPHER_CTX_new()))
	{
		ereport(ERROR,	(errmsg("could not create sm4 xts context: %s",
						fc_SSLerrmessage(ERR_get_error()))));		
	}

	if(1 != EVP_EncryptInit_ex(fc_ctx, EVP_sm4_xts(), NULL, fc_state->pkey, fc_state->iv))
	{
		EVP_CIPHER_CTX_free(fc_ctx);
		ereport(ERROR,	(errmsg("sm4 xts EncryptInit fail: %s",
						fc_SSLerrmessage(ERR_get_error()))));		
	}	


	/* 提供要加密的信息，并获取加密的输出。
	 * 如果需要，可以多次调用EVP_EncryptUpdate
	 */
	if(1 != EVP_EncryptUpdate(fc_ctx, fc_outbuf, &fc_len, fc_inbuf, fc_buflen))
	{
		EVP_CIPHER_CTX_free(fc_ctx);
		ereport(ERROR,	(errmsg("sm4 xts EncryptUpdate fail: %s",
						fc_SSLerrmessage(ERR_get_error()))));		
	}

	if(fc_len != fc_buflen)
	{
		fc_ciphertext_len = fc_len;

		/* 完成加密。此阶段可能会写入更多密文字节。
		 */
		if(1 != EVP_EncryptFinal_ex(fc_ctx, fc_outbuf + fc_len, &fc_len))
		{
			EVP_CIPHER_CTX_free(fc_ctx);
			ereport(ERROR,	(errmsg("sm4 xts EncryptFinal fail: %s",
							fc_SSLerrmessage(ERR_get_error()))));		
		}

		fc_ciphertext_len += fc_len;

		if(fc_ciphertext_len != fc_buflen)
		{
			EVP_CIPHER_CTX_free(fc_ctx);
			ereport(ERROR,	(errmsg("sm4 xts Inconsistent lengths between plaintext(%d) and ciphertext(%d) in Encrypt.",
							fc_buflen,fc_ciphertext_len)));		
		}
	}

	/* 清理 */
	EVP_CIPHER_CTX_free(fc_ctx);
}

/*
* sm4_xts解密函数
*/
static void fc_fdb_sm4_xts_decrypt(struct fdb_cipher_state *const fc_state, const  unsigned char *fc_inbuf, unsigned char *fc_outbuf, int fc_buflen)
{
	EVP_CIPHER_CTX *fc_ctx = NULL;
	int fc_len = 0;
	int fc_plaintext_len = 0;

	/* 创建并初始化上下文 */
	if(!(fc_ctx = EVP_CIPHER_CTX_new()))
	{
		ereport(ERROR,	(errmsg("could not create sm4 xts context: %s",
						fc_SSLerrmessage(ERR_get_error()))));		
	}
	
	if(1 != EVP_DecryptInit_ex(fc_ctx, EVP_sm4_xts(), NULL, fc_state->pkey, fc_state->iv))
	{
		EVP_CIPHER_CTX_free(fc_ctx);
		ereport(ERROR,	(errmsg("sm4 xts DecryptInit fail: %s",
						fc_SSLerrmessage(ERR_get_error()))));		
	}	

	/* 提供要解密的信息，并获取明文输出。
	* 如果需要，可以多次调用EVP_DecryptUpdate
	*/
	if(1 != EVP_DecryptUpdate(fc_ctx, fc_outbuf, &fc_len, fc_inbuf, fc_buflen))
	{
		EVP_CIPHER_CTX_free(fc_ctx);
		ereport(ERROR,	(errmsg("sm4 xts DecryptUpdate fail: %s",
						fc_SSLerrmessage(ERR_get_error()))));		
	}

	if(fc_len != fc_buflen)
	{
		fc_plaintext_len = fc_len;

		/* 完成解密。此阶段可能会写入更多明文字节。
		*/
		if(1 != EVP_DecryptFinal_ex(fc_ctx, fc_outbuf + fc_len, &fc_len))
		{
			EVP_CIPHER_CTX_free(fc_ctx);
			ereport(ERROR,	(errmsg("sm4 xts DecryptFinal fail: %s",
							fc_SSLerrmessage(ERR_get_error()))));		
		}
		
		fc_plaintext_len += fc_len;
		if(fc_plaintext_len != fc_buflen)
		{
			EVP_CIPHER_CTX_free(fc_ctx);
			ereport(ERROR,	(errmsg("sm4 xts Inconsistent lengths between plaintext(%d) and ciphertext(%d) in Decrypt.",
							fc_buflen,fc_plaintext_len)));		
		}
	}

	/* 清理 */
	EVP_CIPHER_CTX_free(fc_ctx);

}
#endif





